﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Input;
using GalaSoft.MvvmLight;
using GalaSoft.MvvmLight.Command;
using VivendoByteToolkit.Controls;
using VivendoByteToolkit.Enums;

namespace VivendoByteToolkit.ViewModels
{
    public class DatePickerViewModel : ViewModelBase
    {
        #region Private properties
        DateTime originalDate;
        int currentSwitch;
        #endregion

        #region Public properties
        public DatePicker DatePicker { get; set; }

        private DateTime date;
        public DateTime Date
        {
            get
            {
                return date;
            }
            set
            {
                date = value;
                this.Day = this.Date.Day.ToString("00");
                this.Month = this.Date.Month.ToString("00");
                this.Year = this.Date.Year.ToString();
                base.RaisePropertyChanged("Date");
            }
        }

        private string day;
        public string Day
        {
            get
            {
                return day;
            }
            set
            {
                day = value;
                base.RaisePropertyChanged("Day");
            }
        }

        private string month;
        public string Month
        {
            get
            {
                return month;
            }
            set
            {
                month = value;
                base.RaisePropertyChanged("Month");
            }
        }

        private string year;
        public string Year
        {
            get
            {
                return year;
            }
            set
            {
                year = value;
                base.RaisePropertyChanged("Year");
            }
        }

        private bool keyboardEnabled;
        public bool KeyboardEnabled
        {
            get
            {
                return keyboardEnabled;
            }
            set
            {
                keyboardEnabled = value;
                base.RaisePropertyChanged("KeyboardEnabled");
            }
        } 
        #endregion

        #region Command
        public ICommand IncrementDayCommand { get; set; }
        public ICommand DecrementDayCommand { get; set; }
        public ICommand SkipUpDayCommand { get; set; }
        public ICommand SkipDownDayCommand { get; set; }
        public ICommand SwitchDayCommand { get; set; }

        public ICommand IncrementMonthCommand { get; set; }
        public ICommand DecrementMonthCommand { get; set; }
        public ICommand SkipUpMonthCommand { get; set; }
        public ICommand SkipDownMonthCommand { get; set; }

        public ICommand IncrementYearCommand { get; set; }
        public ICommand DecrementYearCommand { get; set; }
        public ICommand SkipUpYearCommand { get; set; }
        public ICommand SkipDownYearCommand { get; set; }

        public ICommand TodayCommand { get; set; }
        public ICommand EnableKeyboardCommand { get; set; }
        #endregion

        #region ctor
        public DatePickerViewModel()
        {
            currentSwitch = 0;
            this.Date = DateTime.Now;
            this.UpdateDate();

            this.IncrementDayCommand = new RelayCommand(IncrementDayCommandExecute);
            this.DecrementDayCommand = new RelayCommand(DecrementDayCommandExecute);
            this.SkipUpDayCommand = new RelayCommand(SkipUpDayCommandExecute);
            this.SkipDownDayCommand = new RelayCommand(SkipDownDayCommandExecute);
            this.SwitchDayCommand = new RelayCommand(SwitchDayCommandExecute);

            this.IncrementMonthCommand = new RelayCommand(IncrementMonthCommandExecute);
            this.DecrementMonthCommand = new RelayCommand(DecrementMonthCommandExecute);
            this.SkipUpMonthCommand = new RelayCommand(SkipUpMonthCommandExecute);
            this.SkipDownMonthCommand = new RelayCommand(SkipDownMonthCommandExecute);

            this.IncrementYearCommand = new RelayCommand(IncrementYearCommandExecute);
            this.DecrementYearCommand = new RelayCommand(DecrementYearCommandExecute);
            this.SkipUpYearCommand = new RelayCommand(SkipUpYearCommandExecute);
            this.SkipDownYearCommand = new RelayCommand(SkipDownYearCommandExecute);

            this.TodayCommand = new RelayCommand(TodayCommandExecute);
            this.EnableKeyboardCommand = new RelayCommand(EnableKeyboardCommandExecute);
        } 
        #endregion

        #region Day management
        private void IncrementDayCommandExecute()
        {
            if (DatePicker.GetDayEnabled(this.DatePicker))
            {
                var newDate = this.Date.AddDays(1);

                if (newDate > DatePicker.GetMaximum(this.DatePicker))
                {
                    this.Date = DatePicker.GetMaximum(this.DatePicker);
                }
                else
                {
                    this.Date = newDate;
                }

                this.UpdateDate();
            }
        }

        private void DecrementDayCommandExecute()
        {
            if (DatePicker.GetDayEnabled(this.DatePicker))
            {
                var newDate = this.Date.AddDays(-1);

                if (newDate < DatePicker.GetMinimum(this.DatePicker))
                {
                    this.Date = DatePicker.GetMinimum(this.DatePicker);
                }
                else
                {
                    this.Date = newDate;
                }

                this.UpdateDate();
            }
        }

        private void SkipUpDayCommandExecute()
        {
            if (DatePicker.GetDayEnabled(this.DatePicker))
            {
                var newDate = this.Date.AddDays(10);

                if (newDate > DatePicker.GetMaximum(this.DatePicker))
                {
                    this.Date = DatePicker.GetMaximum(this.DatePicker);
                }
                else
                {
                    this.Date = newDate;
                }

                this.UpdateDate();
            }
        }

        private void SkipDownDayCommandExecute()
        {
            if (DatePicker.GetDayEnabled(this.DatePicker))
            {
                var newDate = this.Date.AddDays(-10);

                if (newDate < DatePicker.GetMinimum(this.DatePicker))
                {
                    this.Date = DatePicker.GetMinimum(this.DatePicker);
                }
                else
                {
                    this.Date = newDate;
                }

                this.UpdateDate();
            }
        } 
        #endregion

        #region Month management
        private void IncrementMonthCommandExecute()
        {
            if (DatePicker.GetMonthEnabled(this.DatePicker))
            {
                var newDate = this.Date.AddMonths(1);

                if (newDate > DatePicker.GetMaximum(this.DatePicker))
                {
                    this.Date = DatePicker.GetMaximum(this.DatePicker);
                }
                else
                {
                    this.Date = newDate;
                }

                this.UpdateDate();
            }
        }

        private void DecrementMonthCommandExecute()
        {
            if (DatePicker.GetMonthEnabled(this.DatePicker))
            {
                var newDate = this.Date.AddMonths(-1);

                if (newDate < DatePicker.GetMinimum(this.DatePicker))
                {
                    this.Date = DatePicker.GetMinimum(this.DatePicker);
                }
                else
                {
                    this.Date = newDate;
                }

                this.UpdateDate();
            }
        }

        private void SkipUpMonthCommandExecute()
        {
            if (DatePicker.GetMonthEnabled(this.DatePicker))
            {
                var newDate = this.Date.AddMonths(3);

                if (newDate > DatePicker.GetMaximum(this.DatePicker))
                {
                    this.Date = DatePicker.GetMaximum(this.DatePicker);
                }
                else
                {
                    this.Date = newDate;
                }

                this.UpdateDate();
            }
        }

        private void SkipDownMonthCommandExecute()
        {
            if (DatePicker.GetMonthEnabled(this.DatePicker))
            {
                var newDate = this.Date.AddMonths(-3);

                if (newDate < DatePicker.GetMinimum(this.DatePicker))
                {
                    this.Date = DatePicker.GetMinimum(this.DatePicker);
                }
                else
                {
                    this.Date = newDate;
                }

                this.UpdateDate();
            }
        } 
        #endregion

        #region Year management
        private void IncrementYearCommandExecute()
        {
            if (DatePicker.GetYearEnabled(this.DatePicker))
            {
                var newDate = this.Date.AddYears(1);

                if (newDate > DatePicker.GetMaximum(this.DatePicker))
                {
                    this.Date = DatePicker.GetMaximum(this.DatePicker);
                }
                else
                {
                    this.Date = newDate;
                }

                this.UpdateDate();
            }
        }

        private void DecrementYearCommandExecute()
        {
            if (DatePicker.GetYearEnabled(this.DatePicker))
            {
                var newDate = this.Date.AddYears(-1);

                if (newDate < DatePicker.GetMinimum(this.DatePicker))
                {
                    this.Date = DatePicker.GetMinimum(this.DatePicker);
                }
                else
                {
                    this.Date = newDate;
                }

                this.UpdateDate();
            }
        }

        private void SkipUpYearCommandExecute()
        {
            if (DatePicker.GetYearEnabled(this.DatePicker))
            {
                var newDate = this.Date.AddYears(2);

                if (newDate > DatePicker.GetMaximum(this.DatePicker))
                {
                    this.Date = DatePicker.GetMaximum(this.DatePicker);
                }
                else
                {
                    this.Date = newDate;
                }

                this.UpdateDate();
            }
        }

        private void SkipDownYearCommandExecute()
        {
            if (DatePicker.GetYearEnabled(this.DatePicker))
            {
                var newDate = this.Date.AddYears(-2);

                if (newDate < DatePicker.GetMinimum(this.DatePicker))
                {
                    this.Date = DatePicker.GetMinimum(this.DatePicker);
                }
                else
                {
                    this.Date = newDate;
                }

                this.UpdateDate();
            }
        }
        #endregion

        private void SwitchDayCommandExecute()
        {
            currentSwitch++;
            int switchCtl = ((int)this.DatePicker.GetValue(DatePicker.SwitchDaysProperty) - 1);
            var mode = ((SwitchDayModes)this.DatePicker.GetValue(DatePicker.SwitchDayModeProperty));

            if (currentSwitch > switchCtl)
            {
                currentSwitch = 0;
            }

            if (mode == SwitchDayModes.Past)
            {
                this.Date = originalDate.AddDays(-currentSwitch);
            }
            else if (mode == SwitchDayModes.Future)
            {
                this.Date = originalDate.AddDays(currentSwitch);
            }
            else if (mode == SwitchDayModes.Split)
            {
                var minimumDate = originalDate.AddDays(-(switchCtl / 2));
                var maximumDate = originalDate.AddDays(switchCtl / 2);

                if (this.Date < maximumDate)
                {
                    this.Date = originalDate.AddDays(currentSwitch);
                }
                else
                {
                    this.Date = minimumDate;
                    currentSwitch = -(switchCtl / 2);
                }
            }
            
            this.Day = this.Date.Day.ToString("00");
            this.Month = this.Date.Month.ToString("00");
            this.Year = this.Date.Year.ToString();
            this.UpdateDependencyProperty();
        }

        private void TodayCommandExecute()
        {
            this.Date = DateTime.Now;
            this.Day = this.Date.Day.ToString("00");
            this.Month = this.Date.Month.ToString("00");
            this.Year = this.Date.Year.ToString();
            this.UpdateDependencyProperty();
        }

        private void EnableKeyboardCommandExecute()
        {
            this.KeyboardEnabled = !this.KeyboardEnabled;
        }

        private void UpdateDate()
        {
            originalDate = this.Date;
            this.Day = this.Date.Day.ToString("00");
            this.Month = this.Date.Month.ToString("00");
            this.Year = this.Date.Year.ToString();
            this.UpdateDependencyProperty();
        }

        private void UpdateDependencyProperty()
        {
            if (this.DatePicker != null)
            {
                this.DatePicker.SetValue(DatePicker.DateProperty, this.Date);
            }
        }
    }
}